package com.qys.livesMall.finance.service.impl;


import com.qys.livesMall.common.constants.Constants;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.finance.dao.FinanceUserAccountDao;
import com.qys.livesMall.finance.enums.AccountTradeTypeEnum;
import com.qys.livesMall.finance.enums.FinanceMessageEnum;
import com.qys.livesMall.finance.event.FinanceUserAccountEvent;
import com.qys.livesMall.finance.mapper.FinanceUserAccountMapper;
import com.qys.livesMall.finance.model.dto.AccountHandle;
import com.qys.livesMall.finance.model.dto.AccountSearch;
import com.qys.livesMall.finance.model.dto.user.AddUserAccount;
import com.qys.livesMall.finance.model.dto.user.FinanceUserAccountDTO;
import com.qys.livesMall.finance.model.entity.user.FinanceUserAccount;
import com.qys.livesMall.finance.service.FinanceUserAccountDetailService;
import com.qys.livesMall.finance.service.FinanceUserAccountService;
import com.qys.livesMall.framework.view.Paging;
import com.qys.livesMall.framework.view.QysPage;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import static com.qys.livesMall.finance.common.FinanceLockPrefix.SHOP_ACCOUNT_LOCK;
import static com.qys.livesMall.finance.common.FinanceLockPrefix.USER_ACCOUNT_LOCK;

/**
 * <p>
 * 店铺余额表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-06-06
 */
@Service("financeUserAccountService")
public class FinanceUserAccountServiceImpl extends AccountBaseServer implements FinanceUserAccountService {

    @Autowired
    private FinanceUserAccountDao userAccountDao;

    @Autowired
    private FinanceUserAccountMapper userAccountMapper;

    @Autowired
    private FinanceUserAccountDetailService userAccountDetailService;
    @Resource
    private  ApplicationContext applicationContext;


    @Override
    public void create(Long userId) {
        if (userAccountDao.getByUserId(userId)!=null){
            return;
        }
        FinanceUserAccount info=new FinanceUserAccount();
        info.setUserId(userId);
        BigDecimal money=new BigDecimal("0.00");
        info.setTotalBalance(money);
        info.setAvailableBalance(money);
        info.setFreezeIn(money);
        info.setFreezeOut(money);
        info.setDeleted(Constants.YesNo.NO);
        userAccountDao.save(info);
    }

    @Override
    public void createBatch(List<AddUserAccount> users) {
        List<FinanceUserAccount> balances=new ArrayList<>();
        users.stream().forEach(shop->{
            FinanceUserAccount info=new FinanceUserAccount();
            info.setUserId(shop.getUserId());
            BigDecimal money=new BigDecimal("0.00");
            info.setTotalBalance(money);
            info.setAvailableBalance(money);
            info.setFreezeIn(money);
            info.setFreezeOut(money);
            info.setDeleted(Constants.YesNo.NO);

            balances.add(info);
        });

        userAccountDao.saveBatch(balances);
    }

    @Override
    public FinanceUserAccount get(Long userId) {
        FinanceUserAccount balance=userAccountDao.getByUserId(userId);
        return balance;
    }

    @Override
    public QysPage<FinanceUserAccount> list(AccountSearch search) {
        Paging<FinanceUserAccount> page=userAccountMapper.search(new Paging<>(search));
        if (CollectionUtils.isEmpty(page.getRecords())){
            return QysPage.build(search);
        }
        return QysPage.to(page);
    }

    @Override
    public List<FinanceUserAccount> listByUserIds(List<Long> userIds) {
        return userAccountDao.getByUserIds(userIds);
    }

    @Override
    public BigDecimal getTotalBalance(Integer userSysType) {
        return userAccountDao.getTotalBalance(userSysType);
    }

    @Override
    public List<String> getSufficientAmountUser(BigDecimal amount) {
        return userAccountMapper.getSufficientAmountUser(amount);
    }

    @Override
    public BigDecimal getSumUserByteam(Long teamId) {
        return userAccountMapper.getSumUserByteam(teamId);
    }

    @Override
    public BigDecimal maxBalanceByUserIds(List<Long> userIds) {
        return userAccountMapper.maxBalanceByUserIds(userIds);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountHandle directIn(AccountHandle handle){
        boolean lock = getLock(USER_ACCOUNT_LOCK, handle.getUserId());
        try{
            if (lock) {
                BigDecimal inMoney = handle.getAmountIncurred().abs();
                FinanceUserAccount info = userAccountDao.getByUserId(handle.getUserId());
                if (info == null) {
                    handle.setMessage(FinanceMessageEnum.SHOP_BALANCE_NOT_EXIST);
                    return handle;
                }
                FinanceUserAccountDTO financeUserAccountDTO=new FinanceUserAccountDTO();
                financeUserAccountDTO.setUnchangedAvailableBalance(info.getAvailableBalance());
                financeUserAccountDTO.setType(0);
                info.setAvailableBalance(info.getAvailableBalance().add(inMoney));
                info.setTotalBalance(info.getTotalBalance().add(inMoney));
                handle.setTradeTypeEnum(AccountTradeTypeEnum.IN);
                //创建变更记录
                handle.setAmountIncurred(inMoney);
                userAccountDetailService.add(handle,info);
                userAccountDao.updateById(info);

                handle.setSuccess(true);
                financeUserAccountDTO.setUserId(info.getUserId());
                financeUserAccountDTO.setAvailableBalance(info.getAvailableBalance());
                applicationContext.publishEvent(new FinanceUserAccountEvent(financeUserAccountDTO));
                return handle;
            }else {
                handle.setSuccess(false);
                handle.setMessage(FinanceMessageEnum.ACCOUNT_BUSY);
                return handle;
            }
        }catch (Exception e){
            throw new QysException(FinanceMessageEnum.ACCOUNT_ERROR);
        }finally {
            if (lock){
                releaseLock(USER_ACCOUNT_LOCK, handle.getUserId());
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountHandle directOut(AccountHandle handle){
        boolean lock = getLock(USER_ACCOUNT_LOCK, handle.getUserId());
        try{
            if (lock) {
                BigDecimal outMoney = handle.getAmountIncurred().abs();
                FinanceUserAccount info = userAccountDao.getByUserId(handle.getUserId());
                if (info == null) {
                    handle.setMessage(FinanceMessageEnum.SHOP_BALANCE_NOT_EXIST);
                    return handle;
                }
                if (info.getAvailableBalance().compareTo(outMoney) == -1) {
                    handle.setMessage(FinanceMessageEnum.USER_BALANCE_BE_NOT_ENOUGH);
                    return handle;
                }
                FinanceUserAccountDTO financeUserAccountDTO=new FinanceUserAccountDTO();
                financeUserAccountDTO.setUnchangedAvailableBalance(info.getTotalBalance());
                financeUserAccountDTO.setType(1);
                info.setTotalBalance(info.getTotalBalance().subtract(outMoney));
                info.setAvailableBalance(info.getAvailableBalance().subtract(outMoney));
                handle.setTradeTypeEnum(AccountTradeTypeEnum.OUT);
                //创建变更记录
                handle.setAmountIncurred(outMoney);
                userAccountDetailService.add(handle,info);
                userAccountDao.updateById(info);

                handle.setSuccess(true);
                financeUserAccountDTO.setUserId(info.getUserId());
                financeUserAccountDTO.setAvailableBalance(info.getAvailableBalance());
                applicationContext.publishEvent(new FinanceUserAccountEvent(financeUserAccountDTO));
                return handle;
                }else {
                handle.setSuccess(false);
                handle.setMessage(FinanceMessageEnum.ACCOUNT_BUSY);
                return handle;
            }
        }catch (Exception e){
            throw new QysException(FinanceMessageEnum.ACCOUNT_ERROR);
        }finally {
            if (lock){
                releaseLock(USER_ACCOUNT_LOCK, handle.getUserId());
            }
        }

    }




}
